﻿using System;
using System.Threading;
using Xenta.Attributes;
using Xenta.Enums;
using Xenta.Operations;
using Xenta.Utils;

namespace Xenta.Tasks
{
    [Dependency("6d3db6cd-e7fb-4a12-b001-78d1ed7601bb")]
    public sealed class LogCleaner : ITask, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private TimeSpan _period;
        private TimeSpan _expPeriod;

        #endregion

        #region Ctors

        public LogCleaner(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _period = TimeSpan.FromDays(3);
            _expPeriod = TimeSpan.FromDays(3);
        }

        #endregion

        #region Properties

        public ThreadPriority Priority
        {
            get
            {
                return ThreadPriority.Normal;
            }
        }

        public TimeSpan Period
        {
            get
            {
                return _period;
            }
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("6d3db6cd-e7fb-4a12-b001-78d1ed7601bb"),
                    IsSafe = true
                });

                try
                {
                    _period = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Period")
                    }).ResultAs(TimeSpan.FromDays(3));
                    _expPeriod = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("ExpPeriod")
                    }).ResultAs(TimeSpan.FromDays(3));
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                }
            }
        }

        public void TaskProc()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("6d3db6cd-e7fb-4a12-b001-78d1ed7601bb"),
                    IsSafe = true
                });

                try
                {
                    processor.Execute(new DeleteLogRecords
                    {
                        CreatedTo = DateTime.UtcNow.Subtract(_expPeriod)
                    });
                    processor.Commit();
                }
                catch(Exception ex)
                {
                    _infrastructure.Log.Error(ex.Message, ex);
                    processor.Rollback();
                }
            }
        }

        #endregion
    }

    [Dependency("f0da333f-c826-4741-9b02-261652077762")]
    public sealed class MessageDispatcher : ITask, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private TimeSpan _period;
        private int _countToSend;
        private int _maxSendAttempCount;

        #endregion

        #region Ctors

        public MessageDispatcher(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _period = TimeSpan.FromMinutes(1);
            _countToSend = 5;
            _maxSendAttempCount = 5;
        }

        #endregion

        #region Properties

        public ThreadPriority Priority
        {
            get
            {
                return ThreadPriority.Normal;
            }
        }

        public TimeSpan Period
        {
            get
            {
                return _period;
            }
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("f0da333f-c826-4741-9b02-261652077762"),
                    IsSafe = true
                });

                try
                {
                    _period = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Period")
                    }).ResultAs(TimeSpan.FromMinutes(1));
                    _countToSend = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("CountToSend")
                    }).ResultAs(5);
                    _maxSendAttempCount = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("MaxSendAttempCount")
                    }).ResultAs(5);
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                }
            }
        }

        public void TaskProc()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("f0da333f-c826-4741-9b02-261652077762"),
                    IsSafe = true
                });

                try
                {
                    foreach(var message in processor.Execute(new SearchMessages
                    {
                        Count = _countToSend,
                        FlagMask = MessageFlags.Active,
                        SendAttemptCountTo = _maxSendAttempCount
                    }).Result)
                    {
                        processor.Execute(new SendMessage
                        {
                            EntityID = message.EntityID
                        });
                    }
                    processor.Commit();
                }
                catch(Exception ex)
                {
                    _infrastructure.Log.Error(ex.Message, ex);
                    processor.Rollback();
                }
            }
        }

        #endregion
    }

    [Dependency("93d56734-3230-49cc-adb4-00265e1d4aa6")]
    public sealed class SessionCleaner : ITask, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private TimeSpan _period;
        private TimeSpan _expPeriod;

        #endregion

        #region Ctors

        public SessionCleaner(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _period = TimeSpan.FromDays(1);
            _expPeriod = TimeSpan.FromDays(14);
        }

        #endregion

        #region Properties

        public ThreadPriority Priority
        {
            get
            {
                return ThreadPriority.Normal;
            }
        }

        public TimeSpan Period
        {
            get
            {
                return _period;
            }
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("93d56734-3230-49cc-adb4-00265e1d4aa6"),
                    IsSafe = true
                });

                try
                {
                    _period = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Period")
                    }).ResultAs(TimeSpan.FromDays(1));
                    _expPeriod = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("ExpPeriod")
                    }).ResultAs(TimeSpan.FromDays(14));
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                }
            }
        }

        public void TaskProc()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("93d56734-3230-49cc-adb4-00265e1d4aa6"),
                    IsSafe = true
                });

                try
                {
                    processor.Execute(new CloseSessions
                    {
                        AccessedTo = DateTime.UtcNow.Subtract(_expPeriod)
                    });
                    processor.Commit();
                }
                catch(Exception ex)
                {
                    _infrastructure.Log.Error(ex.Message, ex);
                    processor.Rollback();
                }
            }
        }

        #endregion
    }

    [Dependency("28786d0c-31b9-455e-a487-caf53a627cee")]
    public sealed class MessageQueueCleaner : ITask, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private TimeSpan _period;
        private TimeSpan _expPeriod;

        #endregion

        #region Ctors

        public MessageQueueCleaner(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _period = TimeSpan.Zero;
            _expPeriod = TimeSpan.FromDays(3);
        }

        #endregion

        #region Properties

        public ThreadPriority Priority
        {
            get
            {
                return ThreadPriority.Normal;
            }
        }

        public TimeSpan Period
        {
            get
            {
                return _period;
            }
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("28786d0c-31b9-455e-a487-caf53a627cee"),
                    IsSafe = true
                });

                try
                {
                    _period = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Period")
                    }).ResultAs(TimeSpan.Zero);
                    _expPeriod = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("ExpPeriod")
                    }).ResultAs(TimeSpan.FromDays(3));
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                }
            }
        }

        public void TaskProc()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("28786d0c-31b9-455e-a487-caf53a627cee"),
                    IsSafe = true
                });

                try
                {
                    processor.Execute(new DeleteMessages
                    {
                        SentTo = DateTime.UtcNow.Subtract(_expPeriod),
                    });
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                    throw;
                }
            }
        }

        #endregion
    }

    [Dependency("eff6fd4b-74f0-474b-9454-b3f27e02664e")]
    public sealed class CurrencyRateUpdate : ITask, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private TimeSpan _period;
        private Guid _providerID;

        #endregion

        #region Ctors

        public CurrencyRateUpdate(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _period = TimeSpan.Zero;
            _providerID = Guid.Empty;
        }

        #endregion

        #region Properties

        public ThreadPriority Priority
        {
            get
            {
                return ThreadPriority.Normal;
            }
        }

        public TimeSpan Period
        {
            get
            {
                return _period;
            }
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("eff6fd4b-74f0-474b-9454-b3f27e02664e"),
                    IsSafe = true
                });

                try
                {
                    _period = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Period")
                    }).ResultAs(TimeSpan.FromMinutes(1));
                    _providerID = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Provider")
                    }).ResultAs<Guid>();
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                }
            }
        }

        public void TaskProc()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("eff6fd4b-74f0-474b-9454-b3f27e02664e"),
                    IsSafe = true
                });

                try
                {
                    processor.Execute(new BulkUpdateCurrencyRatesUsingProvider
                    {
                        ProviderID = _providerID
                    });
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                    throw;
                }
            }
        }

        #endregion
    }

    [Dependency("0abe37c8-22b9-4b64-ad50-b2563e82c0c6")]
    public sealed class OrderMaintainer : ITask, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private TimeSpan _period;
        private TimeSpan _cancelPeriod;
        private TimeSpan _deletePeriod;

        #endregion

        #region Ctors

        public OrderMaintainer(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _period = TimeSpan.Zero;
            _cancelPeriod = TimeSpan.FromDays(3);
            _deletePeriod = TimeSpan.Zero;
        }

        #endregion

        #region Properties

        public ThreadPriority Priority
        {
            get
            {
                return ThreadPriority.Normal;
            }
        }

        public TimeSpan Period
        {
            get
            {
                return _period;
            }
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("0abe37c8-22b9-4b64-ad50-b2563e82c0c6"),
                    IsSafe = true
                });

                try
                {
                    _period = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Period")
                    }).ResultAs(TimeSpan.Zero);
                    _cancelPeriod = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("CancelPeriod")
                    }).ResultAs(TimeSpan.FromDays(3));
                    _deletePeriod = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("DeletePeriod")
                    }).ResultAs(TimeSpan.Zero);
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                }
            }
        }

        public void TaskProc()
        {
            if(_cancelPeriod == TimeSpan.Zero &&
                _deletePeriod == TimeSpan.Zero)
            {
                return;
            }
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("0abe37c8-22b9-4b64-ad50-b2563e82c0c6"),
                    IsSafe = true
                });

                try
                {
                    if(_cancelPeriod != TimeSpan.Zero)
                    {
                        foreach(var i in processor.Execute(new SearchOrders
                        {
                            FlagMask = OrderFlags.Pending,
                            CreatedTo = DateTime.UtcNow.Subtract(_cancelPeriod)
                        }).Result)
                        {
                            try
                            {
                                processor.Execute(new CancelOrder
                                {
                                    EntityID = i.EntityID
                                });
                            }
                            catch(Exception ex)
                            {
                                processor.Execute(new CreateLogRecordFromException
                                {
                                    Ex = ex
                                });
                            }
                        }
                    }
                    if(_deletePeriod != TimeSpan.Zero)
                    {
                        foreach(var i in processor.Execute(new SearchOrders
                        {
                            FlagMask = OrderFlags.Canceled,
                            CreatedTo = DateTime.UtcNow.Subtract(_deletePeriod)
                        }).Result)
                        {
                            try
                            {
                                processor.Execute(new DeleteOrder
                                {
                                    EntityID = i.EntityID
                                });
                            }
                            catch(Exception ex)
                            {
                                processor.Execute(new CreateLogRecordFromException
                                {
                                    Ex = ex
                                });
                            }
                        }
                    }
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                    throw;
                }
            }
        }

        #endregion
    }

    [Dependency("36ab5fc1-a911-4d89-a14c-5be6dd286feb")]
    public sealed class InvoiceMaintainer : ITask, IInitDependencyOnResolve
    {
        #region Fields

        private readonly IInfrastructure _infrastructure;
        private TimeSpan _period;

        #endregion

        #region Ctors

        public InvoiceMaintainer(IInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _period = TimeSpan.Zero;
        }

        #endregion

        #region Properties

        public ThreadPriority Priority
        {
            get
            {
                return ThreadPriority.Normal;
            }
        }

        public TimeSpan Period
        {
            get
            {
                return _period;
            }
        }

        #endregion

        #region Methods

        public void Initialize()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("36ab5fc1-a911-4d89-a14c-5be6dd286feb"),
                    IsSafe = true
                });

                try
                {
                    _period = processor.Execute(new GetConfigParamValueByKey
                    {
                        Key = Par.In("Task").Of(this).Name("Period")
                    }).ResultAs(TimeSpan.FromHours(1));
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                }
            }
        }

        public void TaskProc()
        {
            using(var ioc = _infrastructure.DependencyResolver())
            {
                var processor = ioc.Resolve<IOperationProcessor>().Init(new WorkingContext
                {
                    CID = new Guid("36ab5fc1-a911-4d89-a14c-5be6dd286feb"),
                    IsSafe = true
                });

                try
                {
                    foreach(var i in processor.Execute(new SearchInvoices
                    {
                        IssuedTo = DateTime.UtcNow,
                        FlagMask = InvoiceFlags.Pending
                    }).Result)
                    {
                        try
                        {
                            processor.Execute(new IssueInvoice
                            {
                                EntityID = i.EntityID
                            });
                        }
                        catch(Exception ex)
                        {
                            processor.Execute(new CreateLogRecordFromException
                            {
                                Ex = ex
                            });
                        }
                    }
                    processor.Commit();
                }
                catch
                {
                    processor.Rollback();
                    throw;
                }
            }
        }

        #endregion
    }
}
